const zbActionSheet = function(){
    this.onConfirm = null; //点击确认后执行回调
    this.isConfirm = 0; //是否已点击过确认按钮, 防止频繁点击
    this.files = {}; //选择的图片

    //浮层模板
    this.tpl = '<div id="zbAS" class="zb-flex-col-bottom zb-flex-nowrap zb-width-r100">\
        <div id="zbASMask" class="zb-flex-grow1"></div>\
        <div id="zbASBox" class="zb-flex-col-between zb-flex-stretch">\
          <div id="zbASTitle" class="zb-text-center"></div>\
          <div id="zbASBody"></div>\
          <div id="zbASFooter" class="zb-flex-row-around zb-flex-center">\
           <div class="zbASBtn" id="zbASBtnCancel">取消</div>\
           <div class="zbASBtn" id="zbASBtnConfirm">确认</div>\
          </div>\
         </div>\
         <input type="hidden" id="zbInput" value="">\
        </div>';

    this.init = function (title='') {
        let flag = document.getElementById('zbAS');
        if (flag == null) {
            //初始化css
            this.initCss();

            //初始模板, 绑定事件
            let body = document.getElementsByTagName('body')[0];
            let node = this.htmlToNode(this.tpl);
            node.querySelector('#zbASMask').addEventListener('click', this.hide.bind(this));
            node.querySelector('#zbASBtnCancel').addEventListener('click', this.hide.bind(this));
            node.querySelector('#zbASBtnConfirm').addEventListener('click', this.confirm.bind(this));
            body.appendChild(node);
        }

        document.getElementById('zbASTitle').innerText = title;
    }

    this.htmlToNode = function (html) {
        let div = document.createElement('div');
        div.innerHTML = html;
        return div.firstElementChild;
    }

    //隐藏弹出层
    this.hide = function () {
        document.getElementById('zbAS').style.height = '0';
        document.getElementById('zbASBody').innerHTML = '';
        this.isConfirm = 0;
    }

    //显示弹出层
    this.show = function () {
        document.getElementById('zbAS').style.height = '100%';
    }

    //点击确认按钮触发执行
    this.confirm = function () {
        if (this.isConfirm === 1) {
            console.log('重复点击');
            return;
        }
        this.isConfirm = 1;
        let input = document.getElementById('zbInput');
        let obj = this.decodeObj(input.value);
        input.value = ''; //清空已存储的数据
        this.hide();
        if (typeof this.onConfirm === 'function') {
            this.onConfirm(obj);
        }
    }

    //清除所有的class
    this.clearClass = function(id) {
        let obj = document.getElementById(id);

        let cls = [];
        for (let i=0; i<obj.classList.length; i++) {
            cls.push(obj.classList[i]);
        }

        for (let i=0; i<cls.length; i++) {
            obj.classList.remove(cls[i]);
        }
    }

    //生成样式
    this.initCss = function() {
        let style = document.createElement('style');
        style.innerText =
            '.zb-flex-col-top {display:flex;flex-direction:column;justify-content:flex-start}'+
            '.zb-flex-col-bottom {display:flex;flex-direction:column;justify-content:flex-end}'+
            '.zb-flex-col-between {display:flex;flex-direction:column;justify-content:space-between}'+
            '.zb-flex-col-center {display:flex;flex-direction:column;justify-content:center}'+
            '.zb-flex-col-around {display:flex;flex-direction:column;justify-content:space-around}'+
            '.zb-flex-row-center {display:flex;flex-direction:row;justify-content:center}'+
            '.zb-flex-row-around {display:flex;flex-direction:row;justify-content:space-around}'+
            '.zb-flex-row-between {display:flex;flex-direction:row;justify-content:space-between}'+
            '.zb-flex-row-right {display:flex;flex-direction:row;justify-content:flex-end}'+
            '.zb-flex-stretch {align-items:stretch}'+
            '.zb-flex-center {align-items:center}'+
            '.zb-flex-grow1 {flex-grow:1}'+
            '.zb-flex-nowrap {flex-wrap:nowrap}'+
            '.zb-text-center {text-align:center}'+
            '.zb-scroll-x {overflow-x:scroll; white-space: nowrap;}'+
            '.zb-scroll-x::-webkit-scrollbar {display:none}'+
            '.zb-scroll-y {overflow-y:scroll; white-space: nowrap;}'+
            '.zb-scroll-y::-webkit-scrollbar {display:none}'+
            '.zb-scroll{overflow:scroll; white-space: nowrap;}'+
            '.zb-scroll::-webkit-scrollbar {display:none}'+
            '.zb-width-r100{width:100%;}'+
            '.zb-height-r100{height:100%;}'+
            '#zbAS{position:fixed;top:0;height:0;z-index:200;overflow:hidden;background-color:rgba(0,0,0,0.4);}'+
            '#zbASMask{}'+
            '#zbASBox{max-height:90%;background-color:#fff;border-top-left-radius:6px;border-top-right-radius:6px;}'+
            '#zbASTitle{height:40px;line-height:40px;font-size:20px;border-bottom:1px solid #eeeeee;}'+
            '#zbASBody{min-height:100px;}'+
            //'#zbASSubBody{width:max-content; min-width:100%; min-height:100%;padding:3px;}'+
            '#zbASSubBody{min-height:100%;padding:3px;}'+
            '#zbASFooter{padding:5px;border-top:1px solid #eeeeee;height:40px;line-height:40px;}'+
            '.zbASBtn{width:50%;font-size:20px;text-align:center;}'+
            //'.zb-list{height:max-content;min-height:100%;flex-grow:1;flex-shrink:0;}'+
            '.zb-as-list{flex-grow:1;flex-shrink:0;}'+
            '.zb-as-list-item{height:30px;text-align:center;flex-grow:1;flex-shrink:0;}'+
            '.zb-input{ height:30px;}'+
            '.zb-text{width:100%; max-width:100%; height:100%; min-height:100px; word-wrap:break-word;}'+
            '.zb-response{background-color:#eee}'+
            '.response {animation:bg_color 1s;}'+
            '@keyframes bg_color {from{background:#eee;} to{background:#fff;}}'+
            '@-webkit-keyframes bg_color {from{background:#eee;} to{background:#fff;}}'
        ;

        let head = document.getElementsByTagName('head')[0];
        head.appendChild(style);
    }

    //覆盖指定id的dom元素
    this.replaceNode = function (id, node){
        let old = document.getElementById(id);
        let parent = old.parentNode;
        parent.replaceChild(node, old);
    }

    //添加纵向列表数据
    this.addList = function(data, config={}) {
        let tplList = '<div class="zb-as-list zb-flex-col-start zb-scroll-y" id="{list_id}">{list_item}</div>';
        let tplListItem = '<div class="zb-as-list-item zb-flex-col-center" data-multiple="{multiple}" data-params="{params}">{name}</div>';

        this.clearClass('zbASBody');
        let dataBody = document.getElementById('zbASBody');
        dataBody.classList.add('zb-flex-row-around');
        dataBody.classList.add('zb-scroll-y');

        let multiple = (config && config['multiple'] !== undefined) ? config['multiple'] : '0';

        let listData = [];
        let arrListId = [];
        for (let i=0; i<data.length; i++) {
            let values = data[i]['values'];
            let params = data[i]['params']; //此参数内不能有name,value这俩参数，会被覆盖
            let listId = params['id'];

            // if (listId) {
            //     //如果当前data中有重复的id只会加载一次
            //     if (arrListId.indexOf(listId) !== -1) {
            //         continue;
            //     } else {
            //         arrListId.push(listId);
            //     }
            //
            //     //如果页面中已经存在id=listId的列表, 先删掉
            //     let element=document.getElementById(listId);
            //     if (element) {
            //         console.log('已存在节点 #'+listId);
            //         element.parentNode.removeChild(element);
            //     }
            // }

            let listValues = [];
            if (this.isArray(values)) {
                //非键值对
                for (let i=0; i<values.length; i++) {
                    listValues.push({name: values[i], value:values[i], multiple: multiple});
                }
            } else {
                //键值对
                for (let k in values) {
                    listValues.push({name:values[k], value:k, multiple: multiple});
                }
            }

            // 每一列的值
            let items = this.repeatString(tplListItem, listValues, function(row){
                let p = params;
                p['value'] = row['value'];
                p['name'] = row['name'];
                row['params'] = encodeURIComponent(JSON.stringify(p));

                return row;
            });

            listData.push({list_id:listId, list_item: items});
        }

        //组装每一列, 添加事件绑定
        let listHtml = this.repeatString(tplList, listData);
        let listNode = this.htmlToNode(listHtml);
        let items = listNode.getElementsByClassName('zb-as-list-item');
        for (let i=0; i<items.length; i++) {
            items[i].addEventListener('click', this.changeListParams.bind(items[i]))
        }

        //追加到zbASSubBody中
        dataBody.innerHTML = '<div id="tmp_list"></div>';
        this.replaceNode('tmp_list', listNode);
    }

    //记录点击的list值
    this.changeListParams = function () {
        let multiple = this.getAttribute('data-multiple');
        let params = this.getAttribute('data-params');
        let selected = document.getElementById('zbInput');
        if (multiple === '1') {
            //多选
            let p = JSON.parse(decodeURIComponent(params)); //当前点击的数据
            let v = selected.value ? JSON.parse(decodeURIComponent(selected.value)) : []; //之前点击的数据

            if (this.classList.contains('zb-response')) {
                //删除已选择的项
                this.classList.remove('zb-response');
                let tmp = [];
                for (let i=0; i<v.length;i++) {
                    if (v[i].value !== p.value) {
                        tmp.push(v[i]);
                    }
                }
                selected.value = encodeURIComponent(JSON.stringify(tmp)); //更新已点击的数据
                return true;
            } else {
                v.push(p);
                selected.value = encodeURIComponent(JSON.stringify(v)); //更新已点击的数据
                //高亮当前选中
                this.classList.add('zb-response');
                return true;
            }

        } else {
            //单选
            selected.value = params;

            //清除其他高亮
            let list = document.getElementsByClassName('zb-response');
            for (let i = 0; i < list.length; i++) {
                list[i].classList.remove('zb-response');
            }

            //高亮当前选中
            this.classList.add('zb-response');

            return true;
        }
    }

    //添加文字信息, 文本，日期，数字
    this.addInput = function (config) {
        this.clearClass('zbASBody');
        let box = document.getElementById('zbASBody');
        box.classList.add('zb-flex-col-center');
        box.classList.add('zb-flex-stretch');

        //初始化input标签
        let attrId = 'zb-input'
        let input = document.createElement('input');
        input.setAttribute('id', attrId);
        for (let k in config['attr']) {
            if (k === 'id') {continue}
            input.setAttribute(k, config['attr'][k]);
        }

        input.setAttribute('data-params', this.encodeObj(config['params']));
        input.addEventListener('input', this.changeTextParams.bind(this, attrId))
        input.classList.add('zb-input');
        box.appendChild(input);

        //初始化计数器
        let maxLength = config['attr']['maxlength'] ? config['attr']['maxlength'] : 0;
        if (maxLength > 0) {
            let defaultLength = config['attr']['value'] ? config['attr']['value']['length'] : 0;
            let tpl = '<div class="zb-flex-row-right"><div id="zb-text-length">'+defaultLength+'</div>/<div>'+maxLength+'</div></div>';
            let node = this.htmlToNode(tpl);
            box.appendChild(node);
        }
    }

    //添加文字信息, 可换行
    this.addTextarea = function (config) {
        this.clearClass('zbASBody');
        let box = document.getElementById('zbASBody');
        box.style.height = '500px';
        box.classList.add('zb-flex-col-center');
        box.classList.add('zb-flex-stretch');

        //初始化textarea标签
        let attrId = 'zb-textarea';
        let input = document.createElement('textarea');
        input.setAttribute('id', attrId);
        for (let k in config['attr']) {
            if (k === 'id') {continue};
            input.setAttribute(k, config['attr'][k]);
        }
        input.setAttribute('data-params', this.encodeObj(config['params']));
        input.addEventListener('input', this.changeTextParams.bind(this, attrId))
        input.setAttribute('style', 'height:450px')
        input.innerHTML = (config['value']) ? config['value'] : '';
        box.appendChild(input);

        //初始化计数器
        let maxLength = config['attr']['maxlength'] ? config['attr']['maxlength'] : 0;
        if (maxLength > 0) {
            let defaultLength = config['value'] ? config['value']['length'] : 0;
            let tpl = '<div class="zb-flex-row-right"><div id="zb-text-length">'+defaultLength+'</div>/<div>'+maxLength+'</div></div>';
            let node = this.htmlToNode(tpl);
            box.appendChild(node);
        }
    }

    //输入文本框时, 记录下输入的值, 并实时计算字数
    this.changeTextParams = function (id){
        let obj = document.getElementById(id);
        //变更长度
        let maxLength = obj.getAttribute('maxlength');
        if (maxLength) {
            let currLen = obj.value.length
            document.getElementById('zb-text-length').innerText = (currLen > maxLength) ? maxLength : currLen;
            if (currLen > maxLength) {
                obj.value = obj.value.substring(0, maxLength);
            }
        }

        //记录下输入的值
        let params = obj.getAttribute('data-params');
        let p = this.decodeObj(params);
        p['value'] = obj.value;
        document.getElementById('zbInput').value = this.encodeObj(p);
    }

    //输入图片
    this.addImage = function (config) {
        //初始化input标签
        let input = document.createElement('input');
        //input.setAttribute('id', attrId);
        input.setAttribute('type', 'file');
        for (let k in config['attr']) {
            if (k === 'type') {continue}
            input.setAttribute(k, config['attr'][k]);
        }

        let fileId = config['attr']['id'];
        input.setAttribute('data-params', this.encodeObj(config['params']));
        input.addEventListener('input', this.changeImage.bind(this, fileId, config.image_box_id));

        this.files[fileId] = input;
        this.files[fileId].click(); //触发点击事件, 让用户选择图片
    }

    //改变输入的图片的事件
    this.changeImage = function (id, image_box_id) {
        let fileInput = this.files[id]; //文件input对象
        let objImage = fileInput.files[0];
        if (!objImage.size) {
            alert('未找到图片, 请重新选择');
            return false;
        }

        //回显图片文件名到列表
        let params = document.getElementById(id).getAttribute('params');
        let p = this.decodeObj(params);
        p['value'] = objImage.name;
        document.getElementById('zbInput').value = this.encodeObj(p);
        this.confirm();

        //删除已存在的相同id的图片
        let imageBox = document.getElementById(image_box_id)
        let images = imageBox.getElementsByTagName('img');
        for (let i=0;i<images.length; i++) {
            if (images[i].getAttribute('data-id') === id) {
                imageBox.removeChild(images[i]); //replaceChild();
            }
        }

        //回显图片到页面
        let reader = new FileReader();
        reader.onload = function(evt) {
            let img = document.createElement('img');
            img.setAttribute('data-id', id);
            img.setAttribute('onclick', "image_clicked(this);");
            img.src = evt.target.result;
            imageBox.appendChild(img);
        };

        reader.readAsDataURL(objImage);
    }

    //根据数组, 渲染HTML字符串
    this.repeatString = function (tplDom, arr, func=null) {
        if (!tplDom.length) {
            this.error('字符串长度为空');
            return;
        }

        if (arr.length === 0) {
            this.error('数据为空');
            return tplDom;
        }

        let tpl = tplDom;
        let out = '';
        for (let i=0; i<arr.length; i++) {
            if (typeof func === 'function') {
                arr[i] = func(arr[i]);
            }
            let map = arr[i];
            let tmp = tpl;
            for (let j in map) {
                let re = new RegExp('{' + j + '}', 'g');
                tmp = tmp.replace(re, map[j]);
            }

            let re = new RegExp('{_idx}', 'g');
            tmp = tmp.replace(re, parseInt(i)+1);

            out += tmp;
        }

        return out;
    };

    //是否是数组
    this.isArray = function (o){
        return Object.prototype.toString.call(o) === '[object Array]';
    }

    this.error = function(str) {
        console.log(str);
    }

    this.encodeObj = function (obj) {
        return encodeURIComponent(JSON.stringify(obj));
    }

    this.decodeObj = function (str) {
        return JSON.parse(decodeURIComponent(str));
    }
}
/**
 * 用法举例:

 let zbAS = new zbActionSheet();
 zbAS.init('title');
 zbAS.onConfirm = function(params) {console.log(params)};

 //1. 添加列表
 let data = [{params: {id:'xxx'}, values: {name:'name', value:'value'}}];
 zbAS.addList(data, {multiple:true}); //multiple: true:多选, false:单选
 zbAS.show(); //显示表单

 //2. 单行文本框
 //type: text/date/datetime/number/float等参考input的type属性
 let data = { attr:{id:'xxx', type:'text', maxlength:20, value:defaultValue}, params:{module:module,module_id:id,field:field}};
 zbAS.addInput(data);
 zbAS.show();

 //3. 多行文本框
 let data = {attr:{id:'xxx', maxlength:300}, value:defaultValue, params:{a:'a', b:'b'}};
 zbAS.addTextarea(data);
 zbAS.show();


 //实际用例: 通用表单
 // module:编辑字段所属的模块名; id:数据库中的记录id; field:数据库中的字段名; defaultValue:当前值;
 // config: 当前编辑字段的配置信息， 包括字段注释（name）, 字段类型（data_type[list,string,number,date,text等]）, 步长（step）, 最大长度（maxlength）, 可选值列表（values）等
 // onConfirm: 点击确认后的回调方法, 没有则不触发回调
 let editField = function(config, defaultValue, params, onConfirm) {
    let field = config.field
    let data_type = config.data_type;

    zbAS.init(config.name);
    zbAS.onConfirm = onConfirm;

    if (data_type === 'list') {
        let data = [{params: params, values: config.values}];
        zbAS.addList(data);
        zbAS.show();

    } else if (data_type === 'string') {
        let data = { attr:{id:field, type:'text', maxlength:config.maxlength, value:defaultValue}, params:params};
        zbAS.addInput(data);
        zbAS.show();

    } else if (data_type === 'number') {
        let data = {attr:{id:field, type:'number', step:config.step, maxlength:config.maxlength, value:defaultValue}, params:params};
        zbAS.addInput(data);
        zbAS.show();

    } else if (['date', 'datetime-local'].indexOf(data_type) !== -1) {
        let data = {attr:{id:field, type:data_type, value:defaultValue}, params:params};
        zbAS.addInput(data);
        zbAS.show();

    } else if (data_type === 'text') {
        let data = {attr:{id:field, maxlength:config.maxlength}, value:defaultValue, params};
        zbAS.addTextarea(data);
        zbAS.show();

    } else {
        alert('字段类型不支持');
    }
}
 */